package music;

import music.com.jvspiano.sound.file.MyFileReaderTxt;
import music.com.jvspiano.sound.file.MyStringDistributerIMPL;
import music.com.jvspiano.sound.note.MyNoteIMPL;
import music.com.jvspiano.sound.note.NoteInfo;

import javax.sound.midi.*;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.CopyOnWriteArrayList;

public class Music implements MetaEventListener {
    private String musicName;


    public String getMusicPath() {
        return "F:/File/" + musicName + ".txt";
    }

    public void setMusicName(String musicName) {
        this.musicName = musicName;
    }

    MyStringDistributerIMPL md = new MyStringDistributerIMPL();
    MyFileReaderTxt mf = new MyFileReaderTxt();
    Sequencer player = null;
    String file;
    private boolean reserve = false;

    public void setReserve(boolean reserve) {
        this.reserve = reserve;
    }

    public Music() throws Exception {
        player = MidiSystem.getSequencer();
    }

    public CopyOnWriteArrayList<NoteInfo> getNoteInfoList() {
        return md.getNoteInfoList();
    }

    public long getCurrentTick() {
        return player.getTickPosition();
    }

    public String getFile() {
        return file;
    }

    public void setFile(String file) {
        this.file = file;
    }

    public void saveMidiFile(File file, Sequence sequence) {
        try {
            int[] fileTypes = MidiSystem.getMidiFileTypes(sequence);
            if (fileTypes.length == 0) {
                System.out.println("Can't save sequence");
            } else {
                if (MidiSystem.write(sequence, fileTypes[0], file) == -1) {
                    throw new IOException("Problems writing to file");
                }
            }
        } catch (SecurityException ex) {
            ex.printStackTrace();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    long tick;
    boolean first = true;

    @Override
    public void meta(MetaMessage meta) {
        if (meta.getType() == 127) {
            String data = new String(meta.getData());
            String arr[] = data.split(" ");
            String note = arr[0];
            long currentTick = player.getTickPosition();
            if (tick < currentTick / md.getMyNoteIMPL().getBarTick()) {
                tick = currentTick / md.getMyNoteIMPL().getBarTick();
                System.out.println();
                System.out.print(String.format("%5d:当前第%3d/%3d节:  ", currentTick, (tick + 1), player.getTickLength() / md.getMyNoteIMPL().getBarTick()));
                System.out.print(String.format("%-5s", md.getMyNoteIMPL().calNoteNum(Integer.parseInt(note))));
            } else {
                if (first) {
                    System.out.print(String.format("%5d:当前第%3d/%3d节:  ", currentTick, (tick + 1), player.getTickLength() / md.getMyNoteIMPL().getBarTick()));
                    first = false;
                }
                String s = md.getMyNoteIMPL().calNoteNum(Integer.parseInt(note));
                System.out.print(String.format("%-5s", s));
            }
        } else if (meta.getType() == 47) {
            System.out.println();
            System.out.println("播放完毕");
            player.close();
        } else {
            System.out.println(meta.getType());
        }
    }



    public MyNoteIMPL getMyNoteIMPL() {
        return md.getMyNoteIMPL();
    }

    public float getBPM() {
        return player.getTempoInBPM();
    }

    public String getPPQ() {
        return getMyNoteIMPL().getPpq();
    }

    public void play() throws Exception {

        RandomAccessFile read = mf.Read(file);
        md.distribute(read);
        player.setTempoInBPM(md.getMyNoteIMPL().getBpm());

        player.open();
        Thread.sleep(200);
        if (reserve){
            reversePlay();
        }
        player.setSequence(md.getSequence());
        player.addMetaEventListener(this);
        if (player.getSequence() == null) {
            player.close();
            return;
        }
        player.start();
    }
    private void reversePlay() {
        Track track = md.getSequence().getTracks()[0];
        Track track1 = md.getSequence().createTrack();
        CopyOnWriteArrayList<NoteInfo> noteInfoList = md.getNoteInfoList();
        CopyOnWriteArrayList<NoteInfo> noteInfoList2 = new CopyOnWriteArrayList();

        for (int i = 0; i < track.size(); i++) {
            MidiEvent midiEvent = track.get(i);
            long tick = track.ticks() - midiEvent.getTick();
            midiEvent.setTick(tick);
            track1.add(midiEvent);
        }
        for (int i = noteInfoList.size() - 1; i >= 0; i--) {
            long tick = track1.ticks();
            NoteInfo noteInfo = noteInfoList.get(i);
            noteInfo.setOriginTick(tick - noteInfo.getOriginTick());
            noteInfoList2.add(noteInfo);
        }
        md.setNoteInfoList(noteInfoList2);
        md.getSequence().deleteTrack(track);
    }

    public boolean isRunning() {
        if (player == null)
            return false;
        return player.isRunning();
    }

    public void startz(Music p) throws Exception {
        p.setReserve(false);
        p.setFile(p.getMusicPath());
        p.play();
    }
    public void startn(Music p) throws Exception {
        p.setReserve(true);
        p.setFile(p.getMusicPath());
        p.play();
    }


    public static void main(String[] args) throws Exception{
        int i = 0;
        while(true){
            Music music = new Music();
            switch (i%16) {
                case 0:
                    music.setMusicName("komorebi");
                    break;
                case 1:
                    music.setMusicName("MySoul");
                    break;
                case 2:
                    music.setMusicName("Tassel");
                    break;
                case 3:
                    music.setMusicName("动天");
                    break;
                case 4:
                    music.setMusicName("菊次郎的夏天");
                    break;
                case 5:
                    music.setMusicName("起风了");
                    break;
                case 6:
                    music.setMusicName("悬溺");
                    break;
                case 7:
                    music.setMusicName("夜的钢琴曲五");
                    break;
                case 8:
                    music.setMusicName("komorebi");
                    break;
                case 9:
                    music.setMusicName("MySoul");
                    break;
                case 10:
                    music.setMusicName("Tassel");
                    break;
                case 11:
                    music.setMusicName("动天");
                    break;
                case 12:
                    music.setMusicName("菊次郎的夏天");
                    break;
                case 13:
                    music.setMusicName("起风了");
                    break;
                case 14:
                    music.setMusicName("悬溺");
                    break;
                case 15:
                    music.setMusicName("夜的钢琴曲五");
                    break;
            }
            music.startz(music);
            Thread.sleep(2700 * music.player.getTickLength() / music.md.getMyNoteIMPL().getBarTick());
            i++;
        }
    }


}